#lang racket
(require rackunit)
(require racket/generic)
(provide (all-defined-out))

;; Values
(define (r:value? v) (or (r:number? v) (r:bool? v)))
(struct r:number (value) #:transparent)
(struct r:bool (value) #:transparent)

;; Expressions
(define (r:expression? e)
  (or (r:value? e)
      (r:variable? e)
      (r:apply? e)))

(struct r:variable (name) #:transparent)

(struct r:apply (func args) #:transparent)

(define (r:quote exp)
  (match exp
    [(r:number n) n]
    [(r:bool b) b]
    [(r:variable x) x]
    [(r:apply ef ea) (cons (r:quote ef) (map r:quote ea))]))

(check-equal? (r:quote (r:number 10)) 10)
(check-equal? (r:quote (r:variable 'x)) 'x)
(check-equal?
  (r:quote
    (r:apply (r:variable 'foo)
             (list (r:number 10) (r:variable 'x))))
  '(foo 10 x))

(check-equal? (r:quote (r:apply (r:variable 'and) (list (r:bool #t) (r:bool #f))))
  '(and #t #f))
#|
(r:quote
  (r:apply (r:variable 'and)
           (list (r:bool #f) (r:bool #t))))
|#
#|
(r:quote
    (r:apply (r:variable 'foo)
             (list (r:number 10) (r:variable 'x))))
|#



























;